from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from rest_framework import serializers
from django_redis import get_redis_connection
from rest_framework.exceptions import ValidationError
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
import re
from config.dbs.redisConfig import KEY_TEMPLATE
from users.models import UserDetail,Area,Address


class UserSerializer(serializers.ModelSerializer):
    # 新增 验证码 uuid的 校验  反序列化
    # 前端能传入 write_only 能写
    verify = serializers.CharField(write_only=True)
    uuid = serializers.CharField(write_only=True)

    phone = serializers.CharField(source="userdetail.phone", read_only=True)
    sex = serializers.IntegerField(source="userdetail.sex", read_only=True)
    birthday = serializers.CharField(source="userdetail.birthday", read_only=True)
    avatar = serializers.CharField(source="userdetail.avatar", read_only=True)

    class Meta:
        model = User
        # fields = "__all__"

        exclude = ["first_name", "groups", "date_joined"
                    , "last_login", "user_permissions", "is_staff",
                    "is_active"]
        extra_kwargs = {
            "password": {"write_only": True},
            "is_superuser": {"read_only": True},
        }
    # 自定义校验规则
    # 对象级别的校验
    # 拿到前端的 uuid 和 verify
    # 拿到redis的 验证码 进行比对
    def validate(self, attrs):
        # attrs = {"username":"username","verify:"","uuid":""}
        verify = attrs.get('verify')  # abcd
        uuid = attrs.get('uuid')
        # 吧redis连接信息 作为参数  ==》redis缓存对象
        cache = get_redis_connection(alias='verify_codes')
        # 读取验证码内容
        redis_verify = cache.get(KEY_TEMPLATE % ("register",uuid))  # abcd
        # 当客户端输入一次验证码后  后端读取一次验证码后  验证码从数据库中删除---避免被暴力枚举
        cache.delete(KEY_TEMPLATE % ("register",uuid))

        #判断有没有验证码
        if not redis_verify:
            raise serializers.ValidationError("验证码过期")
        #判断验证码一不一致
        if verify.upper() != redis_verify.upper():
            raise serializers.ValidationError("验证码错误")
        #校验通过
        return attrs

class MyTokenTokenObtainPairSerializer(TokenObtainPairSerializer):
    # serializers.Serializer  《==密码的校验《===TokenObtainSerializer  《==TokenObtainPairSerializer ===》 token返回
    # 反序列化的时候  能够让客户端传入 uuid  verify
    verify = serializers.CharField(write_only=True)
    uuid = serializers.CharField(write_only=True)

    #校验
    #对象级别
    def validate(self, attrs):
        verify = attrs.get('verify')
        uuid = attrs.get('uuid')
        username = attrs.get('username')
        password = attrs.get('password')

        # 校验  和数据库校验
        # uuid verify的校验  ===》 redis数据校验
        # 吧redis连接信息 作为参数  ==》redis缓存对象
        cache = get_redis_connection(alias='verify_codes')
        #读取验证码内容
        redis_verify = cache.get(KEY_TEMPLATE % ("login",uuid))
        # 当客户端输入一次验证码后  后端读取一次验证码后  验证码从数据库中删除
        cache.delete(KEY_TEMPLATE % ("login", uuid))

        # 判断是否有验证码
        if not redis_verify:
            raise serializers.ValidationError("验证码已过期")
        # 判断验证码是否一致
        if verify.upper() != redis_verify.upper():
            raise serializers.ValidationError("验证码错误")

        # 用户名和密码的校验
        user = authenticate(username=username, password=password)
        if not user:
            raise serializers.ValidationError("账号密码错误")

        # 保持会话状态 制作token令牌
        refresh = self.get_token(user)
        # 返回token 返回到客户端进行保存
        return {'user': user.username, "token": str(refresh.access_token)}


# 用户详情的序列器
class UserDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserDetail
        exclude = ["is_delete"]

class UpdatePasswordSerializer(serializers.Serializer):
    password = serializers.CharField(max_length=16,min_length=6)
    new_password = serializers.CharField(max_length=16,min_length=6)
    re_new_password = serializers.CharField(max_length=16,min_length=6)

    def validate(self, attrs):
        if attrs['new_password'] != attrs['re_new_password']:
            raise serializers.ValidationError("两次密码不一致")
        if attrs['new_password'] == attrs['password']:
            raise serializers.ValidationError("原密码和新密码一致")

        # 原密码和数据库的密码校验
        # 怎么得到用户的数据  self.context["request"]  获取请求对象
        user = self.context["request"].user   # ---- 在序列化器使用这个方法，在视图直接使用 user = request.user
        # user用户信息。check_password(输入密码)
        if not user.check_password(attrs.get('password')):
            raise ValidationError("原密码错误")
        return attrs

#地区序列化器
class AreaSerializer(serializers.ModelSerializer):
    class Meta:
        model = Area
        fields = ["id","name"]

#子集序列化器
class ParentAreaSerializer(serializers.ModelSerializer):
    area_set = AreaSerializer(many=True, read_only=True)
    class Meta:
        model = Area
        fields = ["id","name","area_set"]

#收货地址序列化器
class AddressSerializer(serializers.ModelSerializer):
    province_name = serializers.CharField(source="province.name", read_only=True)
    city_name = serializers.CharField(source="city.name", read_only=True)
    district_name = serializers.CharField(source="district.name", read_only=True)
    class Meta:
        model = Address
        exclude = ["is_delete"]

    #属性级别的校验
    def validate_mobile(self,values):
        if not re.match('1[3-9]\d{9}',values):
            raise serializers.ValidationError("手机号不符合")
        return values

